package com.ms.base.comm.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ms.base.comm.cloud.BaseException;
import com.ms.base.comm.cloud.ResultUtil;
import org.apache.commons.lang.StringUtils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <b>description</b>：框架工具类 <br>
 * <b>time</b>：2018-07-26 18:16 <br>
 * <b>author</b>： ready likun_557@163.com
 */
public class FrameUtil {

    /**
     * 创建arraylist
     *
     * @param args
     * @return
     */
    public static <V> List<V> newArrayList(Object... args) {
        ArrayList list = new ArrayList();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                list.add(args[i]);
            }
        }
        return list;
    }

    /**
     * 创建hashMap
     *
     * @param args
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static <K, V> Map<K, V> newHashMap(Object... args) {
        HashMap paramMap = new HashMap();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                paramMap.put(args[i], args[++i]);
            }
        }
        return paramMap;
    }

    /**
     * 创建LinkedHashMap
     *
     * @param args
     * @return
     */
    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(Object... args) {
        LinkedHashMap paramMap = new LinkedHashMap();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                paramMap.put(args[i], args[++i]);
            }
        }
        return paramMap;
    }

    /**
     * 将对象转换为json字符串
     *
     * @param object 需转换的目标对象
     * @return
     */
    public static String json(Object object) {
        return json(object, false);
    }

    /**
     * 将对象转换为json字符串，可以指定是否格式化
     *
     * @param object 需转换的目标对象
     * @param format 是否格式化
     * @return
     */
    public static String json(Object object, boolean format) {
        if (format) {
            return JSON.toJSONString(object, SerializerFeature.WriteNonStringKeyAsString, SerializerFeature.WriteNullStringAsEmpty,
                    SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat);
        } else {
            return JSON.toJSONString(object, SerializerFeature.WriteNonStringKeyAsString, SerializerFeature.WriteNullStringAsEmpty,
                    SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
        }
    }

    /**
     * 获取list集合中javabean对于的field的值的集合
     *
     * @param list      集合
     * @param fieldName 字段名称
     * @return
     * @throws Exception
     */
    public static <T> List<T> getBeanFieldValues(Collection list, String fieldName) throws Exception {
        if (list != null) {
            List result = FrameUtil.newArrayList();
            for (Object object : list) {
                Field fd = getClassField(fieldName, object.getClass());
                fd.setAccessible(true);
                result.add(fd.get(object));
            }
            return result;
        }
        return null;
    }


    /**
     * 将一个javabean对象转换为map
     *
     * @param keyFieldMap map的键和javaben的field映射
     * @param javabean
     * @return
     * @throws Exception
     */
    @SuppressWarnings({"rawtypes"})
    public static Map<Object, Object> javaBeanToMap(Map<String, String> keyFieldMap, Object javabean) throws Exception {
        if (javabean == null) {
            return null;
        } else {
            Map<Object, Object> map = new LinkedHashMap<Object, Object>();
            Class javabeanClass = javabean.getClass();
            if (keyFieldMap != null) {
                Set<Map.Entry<String, String>> set = keyFieldMap.entrySet();
                for (Map.Entry<String, String> entry : set) {

                    Field field = getClassField(entry.getValue(), javabeanClass);
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                    }
                    map.put(entry.getKey(), field.get(javabean));
                }
            } else {
                Field[] fields = getClassAndParentFields(javabeanClass);
                for (Field field : fields) {
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                    }
                    map.put(field.getName(), field.get(javabean));
                }
            }
            return map;
        }
    }

    /**
     * 将一个javabean对象转换为map
     *
     * @param javabean
     * @return
     * @throws Exception
     */
    public static Map javaBeanToMap(Object javabean) throws Exception {
        return javaBeanToMap(null, javabean);
    }

    /**
     * 获取一个class的某个字段，一直追溯到顶级父class对象
     *
     * @param fieldName
     * @param cs
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Field getClassField(String fieldName, Class cs) {
        for (; cs != Object.class; cs = cs.getSuperclass()) {
            try {
                Field field = cs.getDeclaredField(fieldName);
                if (field != null) {
                    return field;
                }
                field = cs.getField(fieldName);
                if (field != null) {
                    return field;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return null;
    }

    /**
     * 获取一个class对象的所有属性，包括私有以及所有父类的
     *
     * @param cs
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Field[] getClassAndParentFields(Class cs) {
        List<Field> list = new ArrayList<Field>();
        for (; cs != Object.class; cs = cs.getSuperclass()) {
            Field[] fields = cs.getDeclaredFields();
            for (Field field : fields) {
                list.add(field);
            }
        }
        Field[] fs = new Field[list.size()];
        return list.toArray(fs);
    }

    /**
     * 获取一个类中的某个字段
     *
     * @param cs
     * @param name
     * @return
     * @throws Exception
     */
    @SuppressWarnings("rawtypes")
    public static Field getField(Class cs, String name) {
        for (; cs != Object.class; cs = cs.getSuperclass()) {
            try {
                Field field = cs.getDeclaredField(name);
                if (field != null) {
                    return field;
                }
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * 通过反射设置某个对象属性的值
     *
     * @param target     目标对象
     * @param fieldName  字段
     * @param fieldValue 字段值
     * @throws Exception
     */
    public static void setField(Object target, String fieldName, Object fieldValue) throws Exception {
        Field field = getField(target.getClass(), fieldName);
        if (field != null) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            field.set(target, fieldValue);
        }
    }

    /**
     * 通过反射获取某个对象属性的值
     *
     * @param target    目标对象
     * @param fieldName 字段
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    public static <T> T getField(Object target, String fieldName) throws Exception {
        Field field = getField(target.getClass(), fieldName);
        if (field != null) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            return (T) field.get(target);
        }
        return null;
    }

    /**
     * 获取一个class对象的某个方法
     *
     * @param cs
     * @return
     * @throws Exception
     */
    @SuppressWarnings({"rawtypes", "unchecked"})
    public static Method getClassAndParentMethod(Class cs, String name, Class... parameterTypes) throws Exception {
        for (; cs != Object.class; cs = cs.getSuperclass()) {
            Method method = cs.getDeclaredMethod(name, parameterTypes);
            if (method != null) {
                return method;
            }
        }
        return null;
    }

    /**
     * 异常堆栈信息
     *
     * @param throwable
     * @return
     */
    public static String stackTrace(Throwable throwable) {
        StringWriter stringWriter = new StringWriter();
        throwable.printStackTrace(new PrintWriter(stringWriter));
        stringWriter.flush();
        return stringWriter.toString();
    }

    /**
     * 抛出异常
     *
     * @param msg 错误信息
     */
    public static void throwBaseException(String msg) {
        throwBaseException(ResultUtil.ERROR_CODE, null, msg, null);
    }

    /**
     * 抛出异常
     *
     * @param msg     异常信息
     * @param extData 异常扩展信息
     */
    public static void throwBaseException(String msg, Map extData) {
        throwBaseException(ResultUtil.ERROR_CODE, null, msg, extData);
    }

    /**
     * 抛出异常
     *
     * @param code    代码
     * @param subCode 子代码
     * @param msg     错误信息
     */
    public static void throwBaseException(String code, String subCode, String msg, Map extData) {
        throw new BaseException(code, subCode, msg, extData);
    }

    /**
     * @param @param  date 若date为空，返回当前时间
     * @param @return 设定文件
     * @return Long 返回类型
     * @throws
     * @Title: getTime
     * @Description: 获取日期的时间
     */
    public static Long getTime(Date date) {
        if (date == null) {
            date = Calendar.getInstance().getTime();
        }
        return date.getTime() / 1000L;
    }

    /**
     * 获取1997年到当前时间的秒
     *
     * @return Long
     * @date 2015年11月17日 下午12:53:20
     */
    public static Long getTime() {
        return getTime(Calendar.getInstance().getTime());
    }

    /**
     * 将对象转化为字符串，如果对象为null，则返回null
     *
     * @param obj
     * @return
     */
    public static String convertObjToString(Object obj) {
        return obj == null ? null : obj.toString();
    }

    /**
     * map转换为请求参数
     *
     * @param paramMap map对象
     * @param encoder  是否需要url编码
     * @return
     */
    public static String mapToRequestParam(Map<String, Object> paramMap, boolean encoder) {
        try {
            if (paramMap != null && !paramMap.isEmpty()) {
                StringBuilder s = new StringBuilder();
                s.append("?");
                int i = 0;
                for (Map.Entry<String, Object> param : paramMap.entrySet()) {
                    Object value = param.getValue();
                    if (value != null) {
                        if (value.getClass().isArray()) {
                            Object[] obs = (Object[]) value;
                            for (int j = 0; j < obs.length; j++) {
                                String sv = FrameUtil.convertObjToString(obs[j]);
                                s.append(param.getKey())
                                        .append("=")
                                        .append(encoder && StringUtils.isNotBlank(sv) ? URLEncoder.encode(sv, "UTF-8") : sv);
                                if (j < obs.length - 1) {
                                    s.append("&");
                                }
                            }
                        } else {
                            String sv = FrameUtil.convertObjToString(param
                                    .getValue());
                            s.append(param.getKey())
                                    .append("=")
                                    .append(encoder && StringUtils.isNotBlank(sv) ? URLEncoder.encode(sv, "UTF-8") : sv);
                        }
                        if (i < paramMap.size() - 1) {
                            s.append("&");
                        }
                    }
                    i++;
                }
                return s.toString();
            }
            return "";
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * str是否在txtfiles文件中，txtfiles是相对于classpath的路径
     *
     * @param txtFiles 文件列表
     * @param str      匹配的字符串
     * @return
     */
    public static boolean isValidate(List<String> txtFiles, String str) {
        if (txtFiles != null && !txtFiles.isEmpty()) {
            for (String fs : txtFiles) {
                if (StringUtils.isBlank(fs)) {
                    continue;
                }
                List<String> list = TxtFileCacheUtil.get(fs);
                if (list != null) {
                    for (String string : list) {
                        Pattern pattern = Pattern.compile(string);
                        Matcher matcher = pattern.matcher(str);
                        boolean b = matcher.matches();
                        if (b) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * list去重
     *
     * @param list
     * @return
     */
    public static <T> List<T> distinctList(List<T> list) {
        if (list == null) {
            return list;
        }
        List newList = new ArrayList();
        for (Iterator iter = list.iterator(); iter.hasNext(); ) {
            Object element = iter.next();
            if (!newList.contains(element)) {
                newList.add(element);
            }
        }
        return newList;
    }
}
